/**
 *FilePropertyDialog.java
 *@anthor Daniel Liu
 *2006-4-28 5:37:35
 **/
package org.lex.explorer.file;

import java.awt.FlowLayout;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.text.DateFormat;
import java.util.Stack;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSeparator;
import javax.swing.JTextField;
import javax.swing.filechooser.FileView;

import org.lex.io.filesystem.FileSystem;
import org.lex.swing.widgets.EnhancedDialog;
import org.lex.utils.MyTimer;
import org.lex.utils.Pair;
import org.lex.utils.text.DateTimeUtilities;
import org.lex.utils.text.SizeFormat;

/**
 * This code was edited or generated using CloudGarden's Jigloo SWT/Swing GUI
 * Builder, which is free for non-commercial use. If Jigloo is being used
 * commercially (ie, by a corporation, company or business for any purpose
 * whatever) then you should purchase a license for each developer using Jigloo.
 * Please visit www.cloudgarden.com for details. Use of Jigloo implies
 * acceptance of these licensing terms. A COMMERCIAL LICENSE HAS NOT BEEN
 * PURCHASED FOR THIS MACHINE, SO JIGLOO OR THIS CODE CANNOT BE USED LEGALLY FOR
 * ANY CORPORATE OR COMMERCIAL PURPOSE.
 */
public class PropertiesDialog extends EnhancedDialog {
	private static ExecutorService pool = null;
	private static int updateInterval = 500;
	static {
		// ��ʼ������Ŀ¼��С������̳߳�
		pool = Executors.newCachedThreadPool();
	}
	private JButton applyButton = null;
	private JLabel attributeLabel = null;
	private JPanel attributePanel = null;
	private JPanel buttonsPanel = null;
	private JButton cancelButton = null;
	private JTextField fileNameTextField = null;
	private JPanel gluePane = null;
	private JCheckBox hidenCheckBox = null;
	private JLabel iconLabel = null;
	private JLabel locationLabel = null;
	private JTextField locationTextField = null;
	private JLabel modifiedLabel = null;
	private JTextField modifiedTextField = null;
	private JButton okButton = null;
	private JPanel pane = null;
	private JCheckBox readOnlyCheckBox = null;
	private JLabel sizeLabel = null;
	private JTextField sizeTextField = null;
	private JButton touchButton = null;
	private JLabel typeLabel = null;
	private JTextField typeTextField = null;
	private JLabel containsLabel = null;
	private JTextField containsTextField = null;
	private JSeparator bottomSeparator;
	private JSeparator topSeparator;
	private FileView view = null;
	private MyTimer timer = null;
	private SizeCounter sizeCounter = null;

	public PropertiesDialog(Window root) {
		super(root);
		this.view = FileSystem.getLocalFileView();
		initialize();
		timer = new MyTimer(updateInterval) {
			public void actionPerformed(ActionEvent e) {
				sizeTextField.setText(SizeFormat.autoFormat(sizeCounter.size) + " (" + sizeCounter.size + " bytes)");
				containsTextField.setText(sizeCounter.files + " files, " + sizeCounter.folders + " folders");
			}
		};
	}

	public static void showFiles(Window root, File[] files) {
		if (null == files || 0 == files.length)
			return;
		PropertiesDialog d = new PropertiesDialog(root);
		d.setSize(330, 370);
		d.setLocationRelativeTo(root);
		if (1 == files.length)
			d.showFile(files[0]);
		else
			d.showFile(files);
	}

	public void ok() {
		this.apply();
		this.dispose();
	}

	public void cancel() {
		this.dispose();
	}

	public void apply() {
	}

	public void showFile(File file) {
		this.setTitle(file.getName() + " Properties");
		this.iconLabel.setIcon(view.getIcon(file));
		this.fileNameTextField.setText(view.getName(file));
		this.typeTextField.setText(view.getTypeDescription(file));
		this.locationTextField.setText(file.getParent());
		this.modifiedTextField.setText(DateTimeUtilities.formatDateTime(file.lastModified(), DateFormat.LONG));
		this.readOnlyCheckBox.setSelected(!file.canWrite());
		this.hidenCheckBox.setSelected(file.isHidden());
		if (true == file.isDirectory()) {
			Stack<File> files = new Stack<File>();
			files.push(file);
			sizeCounter = new SizeCounter(files);
			pool.execute(sizeCounter);
		} else {
			sizeTextField.setText(SizeFormat.autoFormat(file.length()) + " (" + file.length() + " bytes)");
		}
		this.setVisible(true);
	}

	public void showFile(File[] files) {
		this.setTitle(files[0].getName() + "... Properties");
		this.iconLabel.setIcon(view.getIcon(files[0]));
		Pair<Stack<File>, Pair<String, Long>> count = this.count(files);
		int foldersNumber = count.first().size();
		this.fileNameTextField.setText((files.length - foldersNumber) + " files, " + foldersNumber + " folders");
		this.typeTextField.setText(count.second().first());
		this.locationTextField.setText(files[0].getParent());
		if (0 == foldersNumber) {
			// selected are files
			this.sizeTextField.setText(SizeFormat.autoFormat(count.second().second()) + " (" + count.second().second() + " bytes)");
			this.containsTextField.setText(files.length + " files, 0 folders");
		} else {
			// selected all are folders, no file selected
			sizeCounter = new SizeCounter(count.first());
			pool.execute(sizeCounter);
		}
		this.modifiedTextField.setText("");
		this.readOnlyCheckBox.setSelected(!files[0].canWrite());
		this.hidenCheckBox.setSelected(files[0].isHidden());
		this.setVisible(true);
	}

	/**
	 * �����ӿ�
	 */
	void clean() {
		this.setTitle("");
		this.iconLabel.setIcon(null);
		this.fileNameTextField.setText("");
		this.typeTextField.setText("");
		this.locationTextField.setText("");
		this.sizeTextField.setText("");
		this.modifiedTextField.setText("");
		this.readOnlyCheckBox.setSelected(false);
		this.hidenCheckBox.setSelected(false);
	}

	private Pair<Stack<File>, Pair<String, Long>> count(File[] files) {
		boolean singleType = true;
		long size = 0L;
		String type = view.getTypeDescription(files[0]);
		Stack<File> folders = new Stack<File>();
		for (File file : files) {
			if (true == file.isDirectory())
				folders.push(file);
			else
				size += file.length();
			if (false == view.getTypeDescription(file).equals(type))
				singleType = false;
		}
		if (true == singleType)
			type = "All of type " + type;
		else
			type = "Multiple Types";
		return new Pair<Stack<File>, Pair<String, Long>>(folders, new Pair<String, Long>(type, size));
	}

	/**
	 * ����GUI
	 */
	private void initialize() {
		this.setSize(300, 345);
		this.setContentPane(getPane());
	}

	private JPanel getPane() {
		if (pane == null) {
			containsLabel = new JLabel();
			containsLabel.setText("Contains:");
			attributeLabel = new JLabel();
			attributeLabel.setText("Attribute:");
			modifiedLabel = new JLabel();
			modifiedLabel.setText("Modified:");
			sizeLabel = new JLabel();
			sizeLabel.setText("Size:");
			locationLabel = new JLabel();
			locationLabel.setText("Location:");
			typeLabel = new JLabel();
			typeLabel.setText("Type:");
			iconLabel = new JLabel();
			iconLabel.setText("");
			iconLabel.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
			iconLabel.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
			iconLabel.setIcon(new ImageIcon(getClass().getResource("/lex/resources/images/refresh.png")));
			pane = new JPanel();
			GridBagLayout paneLayout = new GridBagLayout();
			pane.setLayout(paneLayout);
			pane.add(iconLabel, new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(12, 11, 5,
					0), 0, 0));
			pane.add(getFileNameTextField(), new GridBagConstraints(1, 0, 2, 1, 1.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL,
					new Insets(12, 5, 5, 12), 0, 0));
			pane.add(typeLabel, new GridBagConstraints(0, 2, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE,
					new Insets(5, 11, 0, 0), 0, 0));
			pane.add(getTypeTextField(), new GridBagConstraints(1, 2, 2, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL,
					new Insets(5, 5, 0, 12), 0, 0));
			pane.add(locationLabel, new GridBagConstraints(0, 3, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 11,
					5, 0), 0, 0));
			pane.add(getLocationTextField(), new GridBagConstraints(1, 3, 2, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL,
					new Insets(5, 5, 0, 12), 0, 0));
			pane.add(sizeLabel, new GridBagConstraints(0, 4, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE,
					new Insets(5, 11, 5, 0), 0, 0));
			pane.add(getSizeTextField(), new GridBagConstraints(1, 4, 2, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL,
					new Insets(5, 5, 0, 12), 0, 0));
			pane.add(modifiedLabel, new GridBagConstraints(0, 6, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 11,
					5, 0), 0, 0));
			pane.add(getModifiedTextField(), new GridBagConstraints(1, 6, 1, 1, 10.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL,
					new Insets(5, 5, 5, 0), 0, 0));
			pane.add(attributeLabel, new GridBagConstraints(0, 8, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 11,
					5, 0), 0, 0));
			pane.add(getTouchButton(), new GridBagConstraints(2, 6, 1, 1, 0.0, 0.0, GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(5,
					5, 5, 12), 0, 0));
			pane.add(getAttributePanel(), new GridBagConstraints(1, 8, 2, 1, 1.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL,
					new Insets(5, 0, 5, 12), 0, 0));
			pane.add(getGluePane(), new GridBagConstraints(0, 9, 3, 1, 10.0, 10.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0,
					0, 0, 0), 0, 0));
			pane.add(getButtonsPanel(), new GridBagConstraints(0, 10, 3, 1, 1.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL,
					new Insets(0, 5, 12, 6), 0, 0));
			pane.add(containsLabel, new GridBagConstraints(0, 5, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 11,
					5, 0), 0, 0));
			pane.add(getContainsTextField(), new GridBagConstraints(1, 5, 2, 1, 1.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL,
					new Insets(5, 5, 0, 12), 0, 0));
			pane.add(getTopSeparator(), new GridBagConstraints(0, 1, 3, 1, 10.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL,
					new Insets(5, 11, 6, 12), 0, 0));
			pane.add(getBottomSeparator(), new GridBagConstraints(0, 7, 3, 1, 0.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL,
					new Insets(5, 11, 5, 12), 0, 0));
		}
		return pane;
	}

	private JTextField getTypeTextField() {
		if (typeTextField == null) {
			typeTextField = new JTextField();
			typeTextField.setEditable(false);
			typeTextField.setText("type");
			typeTextField.setEnabled(true);
		}
		return typeTextField;
	}

	private JTextField getFileNameTextField() {
		if (fileNameTextField == null) {
			fileNameTextField = new JTextField();
			fileNameTextField.setText("file name");
		}
		return fileNameTextField;
	}

	private JTextField getLocationTextField() {
		if (locationTextField == null) {
			locationTextField = new JTextField();
			locationTextField.setEditable(false);
		}
		return locationTextField;
	}

	private JTextField getSizeTextField() {
		if (sizeTextField == null) {
			sizeTextField = new JTextField();
			sizeTextField.setText("1.32GB( 130,682,112 bytes)");
			sizeTextField.setEditable(false);
		}
		return sizeTextField;
	}

	private JTextField getContainsTextField() {
		if (containsTextField == null) {
			containsTextField = new JTextField();
			containsTextField.setEditable(false);
			containsTextField.setText("1 File");
		}
		return containsTextField;
	}

	private JTextField getModifiedTextField() {
		if (modifiedTextField == null) {
			modifiedTextField = new JTextField();
			modifiedTextField.setEditable(false);
			modifiedTextField.setText("modified");
		}
		return modifiedTextField;
	}

	private JButton getTouchButton() {
		if (touchButton == null) {
			touchButton = new JButton();
			touchButton.setText("");
			touchButton.setIcon(new ImageIcon(getClass().getResource("/lex/resources/images/refresh.png")));
			touchButton.setToolTipText("Touch");
			touchButton.setPreferredSize(new java.awt.Dimension(22, 22));
			touchButton.setMaximumSize(new java.awt.Dimension(22, 22));
		}
		return touchButton;
	}

	private JPanel getAttributePanel() {
		if (attributePanel == null) {
			FlowLayout flowLayout = new FlowLayout();
			flowLayout.setAlignment(FlowLayout.LEFT);
			flowLayout.setAlignOnBaseline(true);
			flowLayout.setVgap(0);
			attributePanel = new JPanel();
			attributePanel.setLayout(flowLayout);
			attributePanel.add(getReadOnlyCheckBox(), null);
			attributePanel.add(getHidenCheckBox(), null);
		}
		return attributePanel;
	}

	private JCheckBox getReadOnlyCheckBox() {
		if (readOnlyCheckBox == null) {
			readOnlyCheckBox = new JCheckBox();
			readOnlyCheckBox.setText("Read Only");
		}
		return readOnlyCheckBox;
	}

	private JCheckBox getHidenCheckBox() {
		if (hidenCheckBox == null) {
			hidenCheckBox = new JCheckBox();
			hidenCheckBox.setText("Hidden");
			hidenCheckBox.setSelected(true);
			hidenCheckBox.setEnabled(false);
		}
		return hidenCheckBox;
	}

	private JPanel getGluePane() {
		if (gluePane == null) {
			gluePane = new JPanel();
		}
		return gluePane;
	}

	private JPanel getButtonsPanel() {
		if (buttonsPanel == null) {
			buttonsPanel = new JPanel();
			FlowLayout buttonsPanelLayout = new FlowLayout();
			buttonsPanelLayout.setAlignOnBaseline(true);
			buttonsPanelLayout.setAlignment(FlowLayout.RIGHT);
			buttonsPanelLayout.setVgap(0);
			buttonsPanel.setLayout(buttonsPanelLayout);
			buttonsPanel.add(getOkButton());
			buttonsPanel.add(getCancelButton());
			buttonsPanel.add(getApplyButton());
		}
		return buttonsPanel;
	}

	private JButton getOkButton() {
		if (okButton == null) {
			okButton = new JButton();
			okButton.setText("OK");
			okButton.addActionListener(new ActionListener() {
				public void actionPerformed(ActionEvent e) {
					ok();
				}
			});
		}
		return okButton;
	}

	private JButton getApplyButton() {
		if (applyButton == null) {
			applyButton = new JButton();
			applyButton.setText("Apply");
			applyButton.setEnabled(false);
			applyButton.addActionListener(new ActionListener() {
				public void actionPerformed(ActionEvent e) {
					apply();
				}
			});
		}
		return applyButton;
	}

	private JButton getCancelButton() {
		if (cancelButton == null) {
			cancelButton = new JButton();
			cancelButton.setText("Cancel");
			cancelButton.addActionListener(new ActionListener() {
				public void actionPerformed(ActionEvent e) {
					cancel();
				}
			});
		}
		return cancelButton;
	}

	private JSeparator getTopSeparator() {
		if (topSeparator == null) {
			topSeparator = new JSeparator();
		}
		return topSeparator;
	}

	private JSeparator getBottomSeparator() {
		if (bottomSeparator == null) {
			bottomSeparator = new JSeparator();
		}
		return bottomSeparator;
	}

	class SizeCounter implements Runnable {
		private int folders = 0;
		private int files = 0;
		private long size = 0L;
		private boolean isCancelled = false;
		private Stack<File> queue = null;

		SizeCounter(Stack<File> files) {
			this.queue = files;
		}

		public void cancel() {
			this.isCancelled = true;
		}

		public void run() {
			timer.start();
			while (false == Thread.currentThread().isInterrupted() && false == isCancelled && false == queue.isEmpty()) {
				File file = queue.pop();
				File[] children = file.listFiles();
				if (null == children)
					break;
				for (File child : children) {
					if (true == child.isDirectory()) {
						queue.push(child);
						folders++;
					} else {
						files++;
						size += child.length();
					}
				}
			}
			timer.actionPerformed(null);
			timer.stop();
		}
	}
}
